package com.dfs.parent.service.service;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.dfs.parent.common.core.Model.BaseModel;
import com.dfs.parent.common.core.utils.SnowflakeIdWorkerUtil;
import com.dfs.parent.common.core.utils.SpringContextUtil;
import com.dfs.parent.common.core.utils.StrKit;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @Description TODO
 * @Author dahong
 * @Date 2025/8/15 22:14
 */

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public abstract class BaseService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {
    public T findById(Long id) {
            return this.getById(id);
        }


        @Override
        public boolean updateById(T po) {
            boolean isUpdate = super.updateById(po);

            return isUpdate;
        }

        public boolean removeById(Long id) {
            boolean isRemove = super.removeById(id);
            return isRemove;
        }


        public boolean removeByIds(List<Long> idList) {
            if (ArrayUtil.isEmpty((List) idList)) {
                return false;
            }
            boolean isRemoves = super.removeByIds(idList);
            return isRemoves;
        }

        public boolean saveOrUpdate(T entity) {
            Class<?> clazz = entity.getClass();
            Boolean isSaveOrUpdate = false;
            try {
                Field field = clazz.getDeclaredField("id");
                field.setAccessible(true);
                Long id = (Long) field.get(entity);
                Optional<Long> optional = Optional.ofNullable(id);
                if (optional.isPresent()) {
                    isSaveOrUpdate = updateById(entity);
                } else {
                    isSaveOrUpdate = save(entity);
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return isSaveOrUpdate;
        }

        @Override
        public boolean save(T entity) {
            Class<?> clazz = entity.getClass();
            boolean isSave = false;
            try {
                Field field = clazz.getDeclaredField("id");
                field.setAccessible(true);
                Long id = (Long) field.get(entity);
                Optional<Long> optional = Optional.ofNullable(id);
                if (!optional.isPresent()) {
                    // 雪花算法
                    SnowflakeIdWorkerUtil idWorker = new SnowflakeIdWorkerUtil(0, 0);
                    id = idWorker.nextId();
                    field.set(entity, id);
                }
                isSave = super.save(entity);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return isSave;
        }


        public void join(Page<? extends BaseModel> page, String joinOnField) {
            join(page.getRecords(), joinOnField);
        }

        public void join(Page<? extends BaseModel> page, String joinOnField, String[] needFields){
            join(page.getRecords(), joinOnField, needFields);
        }

        public void join(Page<? extends BaseModel> page, String joinOnField, String joinName) {
            this.join(page.getRecords(), joinOnField, joinName);
        }

        public void join(Page<? extends BaseModel> page, String joinOnField, String joinName, String[] needFields) {
            this.join(page.getRecords(), joinOnField, joinName, needFields);
        }

        /**
         * @param baseModelList 需要合并的model集合
         * @param joinOnField   model对应的field名
         */
        public void join(List<? extends BaseModel> baseModelList, String joinOnField){
            if (ArrayUtil.isNotEmpty(baseModelList)) {
                for (BaseModel m : baseModelList) {
                    join(m, joinOnField);
                }
            }
        }

        public void join(List<? extends BaseModel> baseModelList, String joinOnField, String[] needFields){
            if (ArrayUtil.isNotEmpty(baseModelList)) {
                for (BaseModel m : baseModelList) {
                    join(m, joinOnField, needFields);
                }
            }
        }

        public void join(List<? extends BaseModel> models, String joinOnField, String joinName) {
            if (ArrayUtil.isNotEmpty(models)) {
                for (BaseModel m : models) {
                    join(m, joinOnField, joinName);
                }
            }
        }

        public void join(List<? extends BaseModel> models, String joinOnField, String joinName, String[] needFields) {
            if (ArrayUtil.isNotEmpty(models)) {
                for (BaseModel m : models) {
                    join(m, joinOnField, joinName, needFields);
                }
            }
        }

        /**
         * 合并数据
         *
         * @param model       需要合并的model
         * @param joinOnField model对应的field名
         * @param needFields  T对应的model需要合并到m的field名
         */
        public void join(BaseModel model, String joinOnField, String[] needFields) {
            if (model == null || joinOnField == null) {
                return;
            }
            Long id = (Long) model.get(joinOnField);
            if (null == id) {
                return;
            }

            Object m =  SpringContextUtil.getBean(this.getClass()).findById(id);
//       Object po = this.findById(id);
//        Class<?> clazz= SpringContextUtil.getBean(this.getClass()).getClass();
//        Method method = clazz.getDeclaredMethod("findById", String.class);
//        Object po = method.invoke(SpringContextUtil.getBean(this.getClass()),id);
//        Object po = method.invoke(clazz.newInstance(),id);
            if (m == null) {
                return;
            }
            Map<String, Object> resMap = new HashMap<>();
            for (String fieldName : needFields) {
                // Object o = null;
                try {
                    Field f = m.getClass().getDeclaredField(fieldName);
                    f.setAccessible(true);
                    //  o = f.get(m);
                    resMap.put(fieldName, f.get(m));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                model.put(StrKit.firstCharToLowerCase(m.getClass().getSimpleName()), resMap);
            }
        }

        public void join(BaseModel model, String joinOnField) {
            if (model == null || joinOnField == null) {
                return;
            }
            Long id = (Long) model.get(joinOnField);
            if (null == id) {
                return;
            }

            Object m =  SpringContextUtil.getBean(this.getClass()).findById(id);
            if (m == null) {
                return;
            }
            model.put(StrKit.firstCharToLowerCase(m.getClass().getSimpleName()), m);
        }

        public void join(BaseModel model, String joinOnField, String joinName) {
            if (model == null || joinOnField == null) {
                return;
            }
            Long id = (Long) model.get(joinOnField);
            if (id == null) {
                return;
            }
            Object m =  SpringContextUtil.getBean(this.getClass()).findById(id);
            if (m == null) {
                return;
            }
            model.put(joinName, m);
        }

        public void join(BaseModel model, String joinOnField, String joinName, String[] needFields) {
            if (model == null)
                return;
            Long id = (Long) model.get(joinOnField);
            if (id == null) {
                return;
            }
            Object m =  SpringContextUtil.getBean(this.getClass()).findById(id);
            if (m == null) {
                return;
            }
            Map<String, Object> resMap = new HashMap<>();

            for (String fieldName : needFields) {
                try {
                    Field f = m.getClass().getDeclaredField(fieldName);
                    f.setAccessible(true);
                    resMap.put(fieldName, f.get(m));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            model.put(joinName, resMap);

//        if (m != null) {
//            m = m.copy();
//            m.keep(attrs);
//            model.put(joinName, m);
//        }

        }

    }
